package co.edu.sd.jxta;

import co.edu.sd.jxta.advertisements.AdvertisementsMSPFactory;
import co.edu.sd.jxta.msn.MessageMSPFactory;
import co.edu.sd.jxta.service.ServiceType;
import co.edu.sd.jxta.socket.P2PServerSoccket;
import co.edu.sd.jxta.task.IOTask;
import co.edu.sd.jxta.util.FileUtil;
import java.util.Enumeration;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.Advertisement;
import net.jxta.peergroup.PeerGroup;
import net.jxta.platform.NetworkManager;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import net.jxta.endpoint.Message;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.socket.JxtaServerSocket;

/**
 *
 * @author SD
 */
public class Peer extends Thread
        implements Runnable, IPeer {

    private NetworkManager manager;
    private DiscoveryService discovery;
    private static PeerGroup netPeerGroup = null;
    private static Logger logger = Logger.getLogger(Peer.class.getName());
    private Thread daemon;
    private List<PipeAdvertisement> appAdvertisements = new ArrayList<PipeAdvertisement>();
    private IPeerUI peerUI;

    /**
     * 
     */
    public Peer(String name, Properties availableAdvertisements, IPeerUI peerUI, boolean clearCache) {
        if (peerUI == null) {
            peerUI = new FakePeerUI();
        }
        this.peerUI = peerUI;

        try {

            if (clearCache) {
                File cache = new File(".cache");

                if (cache.exists() == true) {
                    this.peerUI.append("Deleting JXTA cache folder: " + cache.getAbsolutePath());
                    FileUtil.deleteDir(cache);
                }
            }

            manager = new NetworkManager(NetworkManager.ConfigMode.ADHOC, name,
                    new File(new File(".cache"), "" + name).toURI());

            manager.startNetwork();

        } catch (Exception e) {
            e.printStackTrace();
        //System.exit(-1);
        }

        //Configuring shared folder
        File sharedFolder = new File("MySharedFiles/" + name);

        if (sharedFolder.exists() == false) {
            this.peerUI.append("Creating shared folder: " + sharedFolder.getAbsolutePath());
            sharedFolder.mkdirs();
        }

        this.peerUI.append("Using shared folder: " + sharedFolder.getAbsolutePath());

        //Configuring state folder
        File stateFolder = new File("MySavedStates/" + name);

        if (stateFolder.exists() == false) {
            //this.peerUI.append("State folder exists, deleting it");
            //FileUtil.deleteDir(stateFolder);
            this.peerUI.append("Creating state folder: " + stateFolder.getAbsolutePath());
            stateFolder.mkdirs();
        }

        this.peerUI.append("Using state folder: " + stateFolder.getAbsolutePath());

        //Configuring certificates folder
        File certificatesFolder = new File("MyCertificates/" + name);

        if (certificatesFolder.exists() == false) {
            this.peerUI.append("Creating certificates folder: " + certificatesFolder.getAbsolutePath());
            certificatesFolder.mkdirs();
        }

        /**Loading MyCAConfig*/

        netPeerGroup = manager.getNetPeerGroup();
        boolean connected = manager.waitForRendezvousConnection(12000);
        this.peerUI.append("created peer: " + name);
        this.peerUI.append("connected " + connected);
        discovery = netPeerGroup.getDiscoveryService();

        publish(availableAdvertisements);
        //waitFor();
        start();
    }

    /**
     *
     * @param cmd
     */
    public void searchAdvertisementsByName(Command cmd) {
        logger.info("search " + cmd.getServiceName() + " " + cmd.getNRequestedRemoteAdvertisement());
        try {
            if (cmd.isBLookOnLocal()) {
                discovery.getLocalAdvertisements(DiscoveryService.ADV, "Name", cmd.getServiceName());
            }
        } catch (IOException ex) {
            logger.log(Level.SEVERE, ex.getMessage(), ex);
        }
        discovery.getRemoteAdvertisements(
                null,
                DiscoveryService.ADV,
                "Name",
                cmd.getServiceName(),
                cmd.getNRequestedRemoteAdvertisement(),
                new AsynchronousTask(netPeerGroup, this, cmd, peerUI));
    }

    /**
     *
     */
    private void publish(Properties availableAdvertisements) {

        logger.info("publish enabled for this peer");

        try {
            //first delete old advertisements
            Enumeration eOldAdvertisements = discovery.getLocalAdvertisements(DiscoveryService.ADV, null, null);
            while (eOldAdvertisements.hasMoreElements()) {
                Advertisement oAdvertisement = (Advertisement) eOldAdvertisements.nextElement();
                if (oAdvertisement instanceof PipeAdvertisement) {
                    discovery.flushAdvertisement(oAdvertisement);
                }
            }
            //now public with new PipeIDs
            for (ServiceType st : ServiceType.values()) {
                try {
                    if (availableAdvertisements.getProperty(st.getName()).equals("true")) {
                        PipeAdvertisement adv = AdvertisementsMSPFactory.getAdvertisementByServiceType(st);
                        discovery.publish(adv);
                        discovery.remotePublish(adv);
                        appAdvertisements.add(adv);
                    }
                } catch (NullPointerException npe) {
                }
            }
            Enumeration eCurrentAdvertisements = discovery.getLocalAdvertisements(DiscoveryService.ADV, null, null);
            while (eCurrentAdvertisements.hasMoreElements()) {
                Advertisement oAdvertisement = (Advertisement) eCurrentAdvertisements.nextElement();
                if (oAdvertisement instanceof PipeAdvertisement) {
                    System.out.println("current: " + ((PipeAdvertisement) oAdvertisement).getName());
                }
            }
        //pipeService.createInputPipe(adv, this);
        } catch (IOException ex) {
            logger.log(Level.SEVERE, ex.getMessage(), ex);
            ex.printStackTrace();
        }

    }

    public void start() {
        if (daemon == null) {
            daemon = new Thread(this);
            daemon.start();
        }
    }

    public void run() {

        JxtaServerSocket sockets[] = new JxtaServerSocket[appAdvertisements.size()];
        for (int i = 0; i < sockets.length; i++) {

            new P2PServerSoccket(appAdvertisements.get(i), netPeerGroup, this, peerUI);
        }
    /*
    Command cmd = new Command(ServiceType.APP_EXEC.getName(), 1, false);
    cmd.addParameter("" + Command.ParametersName.APP, "ls");
    searchAdvertisementsByName(cmd);
     */
    }

    public Message searchFile(Message oRequest) {
        boolean found = IOTask.getInstance().find(
                netPeerGroup.getPeerName(),
                MessageMSPFactory.getStringFromMessage(oRequest, null, "" + MessageMSPFactory.Attributes.TAG_FILE_NAME));
        return MessageMSPFactory.createFileSearchResponseMessage(netPeerGroup.getPeerName(), found);
    }

    public Message writeFile(Message msg) {
        IOTask.getInstance().write(netPeerGroup.getPeerName(), msg);
        return MessageMSPFactory.createOperationSuccessMessage(netPeerGroup.getPeerName(), ServiceType.FILE_UPLOAD.getName());
    }

    public void writeFile(List<Message> msgs) {
        IOTask.getInstance().writeFile(netPeerGroup.getPeerName(), msgs, "");
    }

    public Message execute(Message msg) {
        String sCommand = MessageMSPFactory.getStringFromMessage(msg, null, "" + MessageMSPFactory.Attributes.TAG_APP_COMMAND);
        String output = IOTask.getInstance().execute(sCommand);
        return MessageMSPFactory.createExecuteApplicationMessageResponse(netPeerGroup.getPeerName(), output);
    }

    public Message time(Message msg) {
        String output = IOTask.getInstance().time();
        return MessageMSPFactory.createTimeMessageResponse(netPeerGroup.getPeerName(), output);
    }

    public String getPeerName() {
        return netPeerGroup.getPeerName();
    }

    /**
     * class for test
     */
    private class FakePeerUI implements IPeerUI {

        public void append(String msn) {
            System.out.println(manager.getNetPeerGroup().getPeerName() + ":: " + msn);
        }
    }
}


